// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: donggu

#pragma once

#include <memory>
#include <functional>
#include <utility>

namespace coin2::base {

/// safe_bind(function, callee) like std::bind(),
/// but the callback is only invoked when callee is alive.
///
/// Use this function instead of abusing shared_ptr everywhere,
/// which leads to slowdowns and memory leaks.
///
/// example:
///   auto func = safe_bind(&Class::method, shared_from_this());
///   // ---- all shared_ptr is destroyed
///   func(); // no-op
template<typename Callback, typename Callee>
auto safe_bind(Callback&& callback, std::shared_ptr<Callee> callee) {
    return [weak = std::weak_ptr{callee}, callback =
        std::forward<Callback>(callback)](auto&&... args) {
            if (auto shared_ptr = weak.lock()) {
                std::invoke(callback, *shared_ptr, std::forward<decltype(args)>(args)...);
            }
        };
}

}  // namespace coin2::base
